/*
 * v1.2 by tonydon
 */
package cn.txdnet.txweb.utils;

import java.beans.IntrospectionException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import net.sf.cglib.beans.BeanCopier;
import txdnet.util.FieldUtil;

/**
 *
 * @author txdnet
 */
public final class BeanUtil {

    /**
     * 缓存需要自动装载的类属性信息
     */
//    private final static Map<Class<?>,PropertyDescriptor[]> cacheClassPd = new HashMap<Class<?>,PropertyDescriptor[]>();
    private static Map<Class<?>, Field[]> cacheClassFields = new HashMap<Class<?>, Field[]>();

    public static void destroy() {
        cacheClassFields.clear();
        cacheClassFields = null;
    }

    /**
     * 得到缓存类属性信息
     *
     * @param type
     * @return
     * @throws Exception
     */
//    private static PropertyDescriptor[] getClassPropertyDescriptors(Class<?> type) throws Exception{
//        PropertyDescriptor[] propertyDescriptors = cacheClassPd.get(type);
//        if(null==propertyDescriptors){
//            propertyDescriptors = Introspector.getBeanInfo(type).getPropertyDescriptors();
//            synchronized(cacheClassPd){
//            cacheClassPd.put(type, propertyDescriptors);
//            }
//        }
//        if(null == propertyDescriptors){
//            throw new RuntimeException(type.getCanonicalName().concat(" - Cache PropertyDescriptors Is Null."));
//        }
//        return propertyDescriptors;
//    }
    private synchronized static Field[] getClassFields(Class<?> type) throws Exception {
        Field[] fields = cacheClassFields.get(type);
        if (null == fields) {
            Set<Field> fieldset = FieldUtil.getAllEnabledFields(type);
            if (CollectionUtil.isNotEmpty(fieldset)) {
                fields = fieldset.toArray((Field[]) Array.newInstance(Field.class, fieldset.size()));
                cacheClassFields.put(type, fields);
            }
        }
        if (null == fields) {
            throw new RuntimeException(type.getCanonicalName().concat(" - Cache Fields Is Null."));
        }
        return fields;
    }

    /**
     * 因此方法性能略低 已禁止使用，可用来学习 将一个 Map 对象转化为一个 JavaBean 支持的Bean字段类型有
     * String,Byte,Integer,Long,Double
     *
     * @param type 要转化的类型
     * @param map 包含属性值的 map
     * @return 转化出来的 JavaBean 对象
     * @throws IntrospectionException 如果分析类属性失败
     * @throws IllegalAccessException 如果实例化 JavaBean 失败
     * @throws InstantiationException 如果实例化 JavaBean 失败
     * @throws InvocationTargetException 如果调用属性的 setter 方法失败 public static <T> T
     * convertMapToBean(Class<T> type, Map map) throws Exception{
     * PropertyDescriptor[] propertyDescriptors =
     * getClassPropertyDescriptors(type); T obj = type.newInstance(); String
     * propertyName; Class propType; Object arg; Method writeMethod; for
     * (PropertyDescriptor descriptor : propertyDescriptors) { writeMethod =
     * descriptor.getWriteMethod(); propertyName = descriptor.getName(); if
     * (map.containsKey(propertyName)) { propType =
     * descriptor.getPropertyType(); arg = convertObject(map.get(propertyName),
     * propType); writeMethod.invoke(obj, arg); } } return obj; }
     *
     */
    public static <T> T parseMapToBean(Class<T> type, Map map) throws Exception {
        T obj = type.newInstance();
        String propertyName;
        Field[] fields = getClassFields(type);
        for (Field f : fields) {
            f.setAccessible(true);
            propertyName = f.getName();
            if (map.containsKey(propertyName)) {
                Object value = map.get(propertyName);
                if (value == null) {
                    continue;
                }
                f.set(obj, FieldUtil.parseObject(value, f));
            }
        }
        return obj;
    }

    public static <T> T parseRequestToBean(Class<T> type, HttpServletRequest req) throws Exception {
        return parseMapToBean(type, req.getParameterMap());
    }

    /**
     * 因此方法性能略低 已禁止使用，可用来学习 将一个 JavaBean 对象转化为一个 Map
     *
     * @param bean 要转化的JavaBean 对象
     * @return 转化出来的 Map 对象
     * @throws IntrospectionException 如果分析类属性失败
     * @throws IllegalAccessException 如果实例化 JavaBean 失败
     * @throws InvocationTargetException 如果调用属性的 setter 方法失败
     */
//    public static Map parseBeanToMap(Object bean) throws Exception {
//        if(bean==null){
//            return null;
//        }
//        Class type = bean.getClass();
//        Map<String,Object> returnMap = new HashMap<String,Object>();
//        BeanInfo beanInfo = Introspector.getBeanInfo(type);
//        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
//        PropertyDescriptor[] propertyDescriptors = getClassPropertyDescriptors(type);
//        String propertyName;
//        for (PropertyDescriptor descriptor : propertyDescriptors) {
//            Method readMethod = descriptor.getReadMethod();
//            if (!Modifier.isPublic(readMethod.getModifiers())) {
//                readMethod.setAccessible(true);
//            }
//            propertyName = descriptor.getName();
//            if (!propertyName.equals("class")) {
//                returnMap.put(propertyName, readMethod.invoke(bean));
//            }
//        }
//        return returnMap;
//    }
    public static Map<String, Object> parseBeanToMap(Object bean) throws Exception {
        if (bean == null) {
            return Collections.emptyMap();
        }
        Class type = bean.getClass();
        Field[] fields = getClassFields(type);
        Map<String, Object> map = new HashMap<String, Object>(fields.length);
        for (Field f : fields) {
            f.setAccessible(true);
            Object obj = f.get(bean);
            if (obj == null) {
                continue;
            }
            map.put(f.getName(), obj);
        }
        return map;
    }

    /**
     * 复制JAVABEAN属性到新对象
     *
     * @param to_obj
     * @param from_obj
     * @throws Exception
     */
    public static void copyProperties(Object to_obj, Object from_obj) throws Exception {
        BeanCopier copier = BeanCopier.create(from_obj.getClass(), to_obj.getClass(), false);
        copier.copy(from_obj, to_obj, null);
    }
}
